package com.tgra;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL11;

public class MovingCamera {
		
		Camera cam;
	
		Point3D lookAt;
		Point3D eye;
		Vector3D u;
		Vector3D v;
		Vector3D n;
		
		float startTime, meanTime1, meanTime2, meanTime3, endTime;
		Point3D P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13;
		Point3D look1, look2, look3, look4, look5, look6, look7, look8, look9, look10, look11, look12, look13;

		public MovingCamera(Point3D pEye, Point3D pCenter, Vector3D up)
		{
			cam = new Camera(pEye, pCenter, up);
			
			eye = pEye;
			n = Vector3D.difference(pEye, pCenter);
			lookAt = pCenter;
			n.normalize();
			u = Vector3D.cross(up, n);
			u.normalize();
			v = Vector3D.cross(n, u);
			

			startTime = 2.0f;
			endTime = 20.0f;
			meanTime1 = 5.0f;
			meanTime2 = 10.0f;
			meanTime3 = 15.0f;
			
			
			P1 = new Point3D(-1.0f, 3.0f, -1.0f);
			P2 = new Point3D(-1.0f, 3.0f, 6.5f);
			P3 = new Point3D(0.0f, 3.0f, 8.0f);
			P4 = new Point3D(1.0f, 3.0f, 5.0f);
			
			P5 = new Point3D(1.0f, 3.0f, -2.0f);
			P6 = new Point3D(6.5f, 3.0f, -2.0f);
			P7 = new Point3D(9.0f, 3.0f, 3.5f);
			
			P8 = new Point3D(7.0f, 3.0f, 7.0f);
			P9 = new Point3D(6.5f, 3.0f, 6.5f);
			P10 = new Point3D(4.5f, 3.0f, 5.0f);
			
			P11 = new Point3D(2.3f, 3.0f, 4.0f);
			P12 = new Point3D(1.0f, 3.0f, 3.0f);
			P13 = new Point3D(1.5f, 3.0f, 2.5f);
			
			look1 = new Point3D(0.0f, 0.0f, 0.0f);
			look2 = new Point3D(0.5f, 0.0f, 7.5f);
			look3 = new Point3D(1.0f, 0.0f, 9.0f);
			look4 = new Point3D(1.2f, 0.0f, 6.0f);
			
			look5 = new Point3D(4.0f, 0.0f, -2.0f);
			look6 = new Point3D(8.5f, 0.0f, -2.0f);
			look7 = new Point3D(9.0f, 0.0f, 4.5f);
			
			look8 = new Point3D(8.5f, 0.0f, 9.0f);
			look9 = new Point3D(6.5f, 0.0f, 9.0f);
			look10 = new Point3D(5.5f, 0.0f, 7.5f);
			
			look11 = new Point3D(3.3f, 0.0f, 6.0f);
			look12 = new Point3D(2.9f, 0.0f, 4.0f);
			look13 = new Point3D(4.5f, 0.0f, 4.0f);
		}
		
		public Point3D getEye()
		{
			return eye;
		}
		
		public void setModelViewMatrix()
		{
			Vector3D minusEye = Vector3D.difference(new Point3D(0,0,0), eye);
			
			float[] matrix = new float[16];
			matrix[0] = u.x;	matrix[4] = u.y;	matrix[8] = u.z;	matrix[12] = Vector3D.dot(minusEye, u);
			matrix[1] = v.x;	matrix[5] = v.y;	matrix[9] = v.z;	matrix[13] = Vector3D.dot(minusEye, v);
			matrix[2] = n.x;	matrix[6] = n.y;	matrix[10] = n.z;	matrix[14] = Vector3D.dot(minusEye, n);
			matrix[3] = 0;		matrix[7] = 0;		matrix[11] = 0;		matrix[15] = 1;
			
			Gdx.gl11.glMatrixMode(GL11.GL_MODELVIEW);
			Gdx.gl11.glLoadMatrixf(matrix, 0);
		}
		
		public void updateCameraPos(float elapsedTime)
		{
			if(elapsedTime < startTime)
			{
				eye.x = P1.x;
				eye.y = P1.y;
				eye.z = P1.z;
				
			}
			else if (elapsedTime > endTime)
			{
				eye.x = P13.x;
				eye.y = P13.y;
				eye.z = P13.z;
				
				
			}
			else if (elapsedTime > startTime && elapsedTime < meanTime1)
			{
				float t = (elapsedTime - startTime) / (meanTime1 - startTime);
				
				// Calculating position with Bezier.
				eye.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*P1.x
					    + 3*(1.0f - t)*(1.0f - t)*t * P2.x
					    + 3*(1.0f - t)*t*t * P3.x
					    + t*t*t * P4.x;
				
				eye.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*P1.z
					    + 3*(1.0f - t)*(1.0f - t)*t * P2.z
					    + 3*(1.0f - t)*t*t * P3.z
					    + t*t*t * P4.z;
				
			}
			else if (elapsedTime > meanTime1 && elapsedTime < meanTime2)
			{
				float t = (elapsedTime - meanTime1) / (meanTime2 - meanTime1);
				
				// Calculating position with Bezier.
				eye.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*P4.x
					    + 3*(1.0f - t)*(1.0f - t)*t * P5.x
					    + 3*(1.0f - t)*t*t * P6.x
					    + t*t*t * P7.x;
				
				eye.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*P4.z
					    + 3*(1.0f - t)*(1.0f - t)*t * P5.z
					    + 3*(1.0f - t)*t*t * P6.z
					    + t*t*t * P7.z;
				
			}
			else if (elapsedTime > meanTime2 && elapsedTime < meanTime3 )
			{
				float t = (elapsedTime - meanTime2) / (meanTime3 - meanTime2);
				
				// Calculating position with Bezier.
				eye.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*P7.x
					    + 3*(1.0f - t)*(1.0f - t)*t * P8.x
					    + 3*(1.0f - t)*t*t * P9.x
					    + t*t*t * P10.x;
				
				eye.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*P7.z
					    + 3*(1.0f - t)*(1.0f - t)*t * P8.z
					    + 3*(1.0f - t)*t*t * P9.z
					    + t*t*t * P10.z;
				
			}
			else if (elapsedTime > meanTime3 && elapsedTime < endTime )
			{
				float t = (elapsedTime - meanTime3) / (endTime - meanTime3);
				
				// Calculating position with Bezier.
				eye.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*P10.x
					    + 3*(1.0f - t)*(1.0f - t)*t * P11.x
					    + 3*(1.0f - t)*t*t * P12.x
					    + t*t*t * P13.x;
				
				eye.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*P10.z
					    + 3*(1.0f - t)*(1.0f - t)*t * P11.z
					    + 3*(1.0f - t)*t*t * P12.z
					    + t*t*t * P13.z;
			
				
			}
		
		}
		
		public void cameraLookAt(float elapsedTime)
		{
			if(elapsedTime < startTime)
			{
				lookAt.x = look1.x;
				lookAt.y = look1.y;
				lookAt.z = look1.z;
				
			}
			else if (elapsedTime > endTime)
			{
				lookAt.x = look13.x;
				lookAt.y = look13.y;
				lookAt.z = look13.z;
				
				
			}
			else if (elapsedTime > startTime && elapsedTime < meanTime1)
			{
				float t = (elapsedTime - startTime) / (meanTime1 - startTime);
				
				// Calculating position with Bezier.
				lookAt.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*look1.x
					    + 3*(1.0f - t)*(1.0f - t)*t * look2.x
					    + 3*(1.0f - t)*t*t * look3.x
					    + t*t*t * look4.x;
				
				lookAt.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*look1.z
					    + 3*(1.0f - t)*(1.0f - t)*t * look2.z
					    + 3*(1.0f - t)*t*t * look3.z
					    + t*t*t * look4.z;
				
			}
			else if (elapsedTime > meanTime1 && elapsedTime < meanTime2)
			{
				float t = (elapsedTime - meanTime1) / (meanTime2 - meanTime1);
				
				// Calculating position with Bezier.
				lookAt.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*look4.x
					    + 3*(1.0f - t)*(1.0f - t)*t * look5.x
					    + 3*(1.0f - t)*t*t * look6.x
					    + t*t*t * look7.x;
				
				lookAt.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*look4.z
					    + 3*(1.0f - t)*(1.0f - t)*t * look5.z
					    + 3*(1.0f - t)*t*t * look6.z
					    + t*t*t * look7.z;
				
			}
			else if (elapsedTime > meanTime2 && elapsedTime < meanTime3 )
			{
				float t = (elapsedTime - meanTime2) / (meanTime3 - meanTime2);
				
				// Calculating position with Bezier.
				lookAt.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*look7.x
					    + 3*(1.0f - t)*(1.0f - t)*t * look8.x
					    + 3*(1.0f - t)*t*t * look9.x
					    + t*t*t * look10.x;
				
				lookAt.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*look7.z
					    + 3*(1.0f - t)*(1.0f - t)*t * look8.z
					    + 3*(1.0f - t)*t*t * look9.z
					    + t*t*t * look10.z;
				
			}
			else if (elapsedTime > meanTime3 && elapsedTime < endTime )
			{
				float t = (elapsedTime - meanTime3) / (endTime - meanTime3);
				
				// Calculating position with Bezier.
				lookAt.x = (1.0f - t)*(1.0f - t)*(1.0f - t)*look10.x
					    + 3*(1.0f - t)*(1.0f - t)*t * look11.x
					    + 3*(1.0f - t)*t*t * look12.x
					    + t*t*t * look13.x;
				
				lookAt.z = (1.0f - t)*(1.0f - t)*(1.0f - t)*look10.z
					    + 3*(1.0f - t)*(1.0f - t)*t * look11.z
					    + 3*(1.0f - t)*t*t * look12.z
					    + t*t*t * look13.z;
			
				
			}
		
		}
		
        public void update(float elapsedTime)
        {
                updateCameraPos(elapsedTime);
                cameraLookAt(elapsedTime);
        }

}
